package com.example.libplayer.player;

import android.graphics.Bitmap;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;

import com.example.libplayer.listener.OnCompleteListener;
import com.example.libplayer.listener.OnCutVideoImgListener;
import com.example.libplayer.listener.OnErrorListener;
import com.example.libplayer.listener.OnGlSurfaceViewOncreateListener;
import com.example.libplayer.listener.OnInfoListener;
import com.example.libplayer.listener.OnLoadListener;
import com.example.libplayer.listener.OnPreparedListener;
import com.example.libplayer.listener.OnStopListener;
import com.example.libplayer.listener.Status;
import com.example.libplayer.utils.MyLog;
import com.example.libplayer.opengles.GlSurfaceView;

import java.nio.ByteBuffer;

/**
 * Created by y on 2017-12-13.
 */

public class Player {

    static {
        System.loadLibrary("avutil");
        System.loadLibrary("swresample");
        System.loadLibrary("avcodec");
        System.loadLibrary("avformat");
        System.loadLibrary("swscale");
        System.loadLibrary("postproc");
        System.loadLibrary("avfilter");
        System.loadLibrary("avdevice");
        System.loadLibrary("player");
    }

    /**
     * 播放文件路径
     */
    private String dataSource;
    /**
     * 硬解码mime
     */
    private MediaFormat mediaFormat;
    /**
     * 视频硬解码器
     */
    private MediaCodec mediaCodec;
    /**
     * 渲染surface
     */
    private Surface surface;
    /**
     * opengl surfaceview
     */
    private GlSurfaceView GlSurfaceView;
    /**
     * 视频解码器info
     */
    private MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

    /**
     * 准备好时的回调
     */
    private OnPreparedListener OnPreparedListener;
    /**
     * 错误时的回调
     */
    private OnErrorListener OnErrorListener;
    /**
     * 加载回调
     */
    private OnLoadListener OnLoadListener;
    /**
     * 更新时间回调
     */
    private OnInfoListener OnInfoListener;
    /**
     * 播放完成回调
     */
    private OnCompleteListener OnCompleteListener;
    /**
     * 视频截图回调
     */
    private OnCutVideoImgListener OnCutVideoImgListener;
    /**
     * 停止完成回调
     */
    private OnStopListener OnStopListener;
    /**
     * 是否已经准备好
     */
    private boolean parpared = false;
    /**
     * 时长实体类
     */
    private TimeBean TimeBean;
    /**
     * 上一次播放时间
     */
    private int lastCurrTime = 0;

    /**
     * 是否只有音频（只播放音频流）
     */
    private boolean isOnlyMusic = false;

    private boolean isOnlySoft = false;

    public Player()
    {
        TimeBean = new TimeBean();
    }

    public void setDataSource(String dataSource) {
        this.dataSource = dataSource;
    }

    public void setOnlyMusic(boolean onlyMusic) {
        isOnlyMusic = onlyMusic;
    }

    private void setSurface(Surface surface) {
        this.surface = surface;
    }

    public void setGlSurfaceView(GlSurfaceView GlSurfaceView) {
        this.GlSurfaceView = GlSurfaceView;
        GlSurfaceView.setOnGlSurfaceViewOncreateListener(new OnGlSurfaceViewOncreateListener() {
            @Override
            public void onGlSurfaceViewOncreate(Surface s) {
                if(surface == null)
                {
                    setSurface(s);
                }
                if(parpared && !TextUtils.isDigitsOnly(dataSource))
                {
                    Prepared(dataSource, isOnlyMusic);
                }
            }

            @Override
            public void onCutVideoImg(Bitmap bitmap) {
                if(OnCutVideoImgListener != null)
                {
                    OnCutVideoImgListener.onCutVideoImg(bitmap);
                }
            }
        });
    }


    /**
     * 准备
     * @param url
     */
    private native void Prepared(String url, boolean isOnlyMusic);

    /**
     * 开始
     */
    private native void Start();

    /**
     * 停止并释放资源
     */
    private native void Stop(boolean exit);

    /**
     * 暂停
     */
    private native void Pause();

    /**
     * 播放 对应暂停
     */
    private native void Resume();

    /**
     * seek
     * @param secds
     */
    private native void Seek(int secds);

    /**
     * 设置音轨 根据获取的音轨数 排序
     * @param index
     */
    private native void SetAudioChannels(int index);

    /**
     * 获取总时长
     * @return
     */
    private native int GetDuration();

    /**
     * 获取音轨数
     * @return
     */
    private native int GetAudioChannels();

    /**
     * 获取视频宽度
     * @return
     */
    private native int GetVideoWidth();

    /**
     * 获取视频长度
     * @return
     */
    private native int GetVideoHeidht();

    public int getDuration()
    {
        return GetDuration();
    }

    public int getAudioChannels()
    {
        return GetAudioChannels();
    }

    public int getVideoWidth()
    {
        return GetVideoWidth();
    }

    public int getVideoHeight()
    {
        return GetVideoHeidht();
    }

    public void setAudioChannels(int index)
    {
        SetAudioChannels(index);
    }



    public void setOnPreparedListener(OnPreparedListener OnPreparedListener) {
        this.OnPreparedListener = OnPreparedListener;
    }



    public void setOnErrorListener(OnErrorListener OnErrorListener) {
        this.OnErrorListener = OnErrorListener;
    }

    public void prepared()
    {
        if(TextUtils.isEmpty(dataSource))
        {
            onError(Status.STATUS_DATASOURCE_NULL, "datasource is null");
            return;
        }
        parpared = true;
        if(isOnlyMusic)
        {
            Prepared(dataSource, isOnlyMusic);
        }
        else
        {
            if(surface != null)
            {
                Prepared(dataSource, isOnlyMusic);
            }
        }
    }

    public void start()
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if(TextUtils.isEmpty(dataSource))
                {
                    onError(Status.STATUS_DATASOURCE_NULL, "datasource is null");
                    return;
                }
                if(!isOnlyMusic)
                {
                    if(surface == null)
                    {
                        onError(Status.STATUS_SURFACE_NULL, "surface is null");
                        return;
                    }
                }

                if(TimeBean == null)
                {
                    TimeBean = new TimeBean();
                }
                Start();
            }
        }).start();
    }

    public void stop(final boolean exit)
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Stop(exit);
                if(mediaCodec != null)
                {
                    try
                    {
                        mediaCodec.flush();
                        mediaCodec.stop();
                        mediaCodec.release();
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                    mediaCodec = null;
                    mediaFormat = null;
                }
                if(GlSurfaceView != null)
                {
                    GlSurfaceView.setCodecType(-1);
                    GlSurfaceView.requestRender();
                }

            }
        }).start();
    }

    public void pause()
    {
        Pause();

    }

    public void resume()
    {
        Resume();
    }

    public void seek(final int secds)
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Seek(secds);
                lastCurrTime = secds;
            }
        }).start();
    }

    public void setOnlySoft(boolean soft)
    {
        this.isOnlySoft = soft;
    }

    public boolean isOnlySoft()
    {
        return isOnlySoft;
    }



    private void onLoad(boolean load)
    {
        if(OnLoadListener != null)
        {
            OnLoadListener.onLoad(load);
        }
    }

    private void onError(int code, String msg)
    {
        if(OnErrorListener != null)
        {
            OnErrorListener.onError(code, msg);
        }
        stop(true);
    }

    private void onParpared()
    {
        if(OnPreparedListener != null)
        {
            OnPreparedListener.onPrepared();
        }
    }

    public void mediacodecInit(int mimetype, int width, int height, byte[] csd0, byte[] csd1)
    {
        if(surface != null)
        {
            try {
                GlSurfaceView.setCodecType(1);
                String mtype = getMimeType(mimetype);
                mediaFormat = MediaFormat.createVideoFormat(mtype, width, height);
                mediaFormat.setInteger(MediaFormat.KEY_WIDTH, width);
                mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, height);
                mediaFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, width * height);
                mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(csd0));
                mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(csd1));
                Log.d("y5320", mediaFormat.toString());
                mediaCodec = MediaCodec.createDecoderByType(mtype);
                if(surface != null)
                {
                    mediaCodec.configure(mediaFormat, surface, null, 0);
                    mediaCodec.start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        else
        {
            if(OnErrorListener != null)
            {
                OnErrorListener.onError(Status.STATUS_SURFACE_NULL, "surface is null");
            }
        }
    }

    public void mediacodecDecode(byte[] bytes, int size, int pts)
    {
        if(bytes != null && mediaCodec != null && info != null)
        {
            try
            {
                int inputBufferIndex = mediaCodec.dequeueInputBuffer(10);
                if(inputBufferIndex >= 0)
                {
                    ByteBuffer byteBuffer = mediaCodec.getInputBuffers()[inputBufferIndex];
                    byteBuffer.clear();
                    byteBuffer.put(bytes);
                    mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, pts, 0);
                }
                int index = mediaCodec.dequeueOutputBuffer(info, 10);
                while (index >= 0) {
                    mediaCodec.releaseOutputBuffer(index, true);
                    index = mediaCodec.dequeueOutputBuffer(info, 10);
                }
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    public void setOnLoadListener(OnLoadListener OnLoadListener) {
        this.OnLoadListener = OnLoadListener;
    }

    private String getMimeType(int type)
    {
        if(type == 1)
        {
            return "video/avc";
        }
        else if(type == 2)
        {
            return "video/hevc";
        }
        else if(type == 3)
        {
            return "video/mp4v-es";
        }
        else if(type == 4)
        {
            return "video/x-ms-wmv";
        }
        return "";
    }

    public void setFrameData(int w, int h, byte[] y, byte[] u, byte[] v)
    {
        if(GlSurfaceView != null)
        {
            MyLog.d("setFrameData");
            GlSurfaceView.setCodecType(0);
            GlSurfaceView.setFrameData(w, h, y, u, v);
        }
    }

    public void setOnInfoListener(OnInfoListener OnInfoListener) {
        this.OnInfoListener = OnInfoListener;
    }

    public void setVideoInfo(int currt_secd, int total_secd)
    {
        if(OnInfoListener != null && TimeBean != null)
        {
            if(currt_secd < lastCurrTime)
            {
                currt_secd = lastCurrTime;
            }
            TimeBean.setCurrt_secds(currt_secd);
            TimeBean.setTotal_secds(total_secd);
            OnInfoListener.onInfo(TimeBean);
            lastCurrTime = currt_secd;
        }
    }

    public void setOnCompleteListener(OnCompleteListener OnCompleteListener) {
        this.OnCompleteListener = OnCompleteListener;
    }

    public void videoComplete()
    {
        if(OnCompleteListener != null)
        {
            setVideoInfo(GetDuration(), GetDuration());
            TimeBean = null;
            OnCompleteListener.onComplete();
        }
    }

    public void setOnCutVideoImgListener(OnCutVideoImgListener OnCutVideoImgListener) {
        this.OnCutVideoImgListener = OnCutVideoImgListener;
    }

    public void cutVideoImg()
    {
        if(GlSurfaceView != null)
        {
            GlSurfaceView.cutVideoImg();
        }
    }

    public void setOnStopListener(OnStopListener OnStopListener) {
        this.OnStopListener = OnStopListener;
    }

    public void onStopComplete()
    {
        if(OnStopListener != null)
        {
            OnStopListener.onStop();
        }
    }
}
